/***************************************************************************************************
  *Copyright(C),2010-2016,Sumscope
  *FileName	:  KeyRecordIdHashMap.h
  *Author	:  scofined.qi
  *Version	:  1.0
  *Date		:  2016/09/18
  *Desc		:  //用于主要说明此程序文件完成的主要功能
  *Relation :  
  *Others	:  //其他内容说明
  *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
  *History	:  //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
***************************************************************************************************/
#pragma once

#include "TableColumn.h"
#include <core/container/KeyHashMap.h>
#include <core/container/SHash.h>
#include <string.h>
#include <string>
#include <list>

namespace qb{
	namespace ht{

class KeyRecordIdHashMap{
	struct ColumnKey{
		const char*	ptr;			// 在Alloc中分配,在~Entry中释放
		int			rid;			//
		int			bytes;			// ptr的长度,有效,不包括结尾0
		ColumnKey() :ptr(0), rid(-1), bytes(0){}
        bool operator==(const ColumnKey& key)const
		{
			if (bytes == key.bytes && bytes > 0 && memcmp(ptr, key.ptr, bytes) == 0)
				return true;
			return false;
		}
        unsigned int GetHash()const
		{
            return qb::base::GetFastHash(ptr, bytes, 0);
		}
        void Reset(){ if (ptr)delete[] ptr; ptr = nullptr; bytes = 0; rid = 0; }
	};
	struct Entry{
		Entry*			hashprev;			// 哈西插槽的双链表的后一个
		Entry*			hashnext;			// 哈西插槽的双链表的前一个
		ColumnKey		key;				// 用于标志
		Entry() :hashnext(0), hashprev(0){}
		~Entry(){ key.Reset(); }
	};
	class ObjectPool{
		typedef Entry Type;
        std::list<Type*> m_unused;
		int				m_capcity;		// 默认-1,表示全部缓存
		int				m_allocated;
	public:
		ObjectPool(int capcity = -1) :m_capcity(capcity), m_allocated(0){}
		~ObjectPool(){
            std::list<Type*>::iterator it = m_unused.begin();
			for (; it != m_unused.end(); ++it)
			{
				delete *it;
			}
		}
		int GetCount()const{ return m_unused.size(); }
		int GetCapcity()const{ return m_capcity; }
		int GetAllocated()const{ return m_allocated; }
		void SetCapcity(int capcity){ m_capcity = capcity; }
		Type* Alloc(){
			Type* type = 0;
			if (!m_unused.empty())
			{
				type = m_unused.front();
				m_unused.pop_front();
			}
			else
				type = new Type();
			m_allocated++;
			return type;
		}
		void Free(Type* t){
			m_allocated--;
			if (m_capcity > 0 && (int)m_unused.size() >= m_capcity)
			{
				delete t;
			}
			else
				m_unused.push_back(t);
		}
	};
    typedef qb::base::KeyHashMap<Entry, ColumnKey> ColumnKeyHashMap;
	kDataType			m_data_type;		//
	int					m_key_bytes;		//
	int					m_mem_bytes;		// Entry.key.ptr所占据的内存
	ColumnKeyHashMap	m_hashmap;			// 
	ObjectPool			m_entry_pool;		//
public:
	KeyRecordIdHashMap(kDataType type, int bytes) :m_data_type(type), m_key_bytes(bytes),
		m_mem_bytes(0){
        m_hashmap.Build(qb::base::GetHashPrimeLargerThan(160));
	}
	~KeyRecordIdHashMap()
	{
		int length = m_hashmap.GetLength();
		for (int i = 0; i < length; i++)
		{
			Entry* head = m_hashmap.GetHead(i);
			while (head)
			{
				Entry* temp = head;
				head = head->hashnext;
				delete temp;
			}
		}
		m_hashmap.Clear();
	}
	int GetMemoryBytes()const{ 
		int bytes= m_hashmap.GetBytes() + sizeof(*this);
		bytes += (m_entry_pool.GetAllocated() + m_entry_pool.GetCount())*(sizeof(Entry));
		bytes += m_mem_bytes;
		return bytes;
	}
	int find(const void* key)
	{
		if (key == nullptr)return -1;
		ColumnKey ckey;
		ckey.ptr = (const char*)key;
		ckey.bytes = strlen(ckey.ptr);
		ckey.rid = -1;
		unsigned int hash = ckey.GetHash();
		Entry* et = m_hashmap.Find(ckey, hash);
		return et ? et->key.rid : -1;
	}
	bool insert(const void* key,int len, int rid)
	{
		if (key == nullptr)return false;
		Entry* et = Alloc(key,len, rid);
		m_hashmap.Insert(et, et->key.GetHash());

		// 默认负载比例为2.0
		if (m_hashmap.GetCount() > m_hashmap.GetLength()*2.0)
		{
			Expand(m_hashmap.GetCount());
		}
		return true;
	}
	bool remove(const void* key)
	{
		if (key == nullptr)return false;
		ColumnKey ckey;
		ckey.ptr = (const char*)key;
		ckey.bytes = strlen(ckey.ptr);
		ckey.rid = -1;
		unsigned int hash = ckey.GetHash();
		Entry* et =m_hashmap.Remove(ckey, hash);
		if (et)
		{
			m_mem_bytes -= et->key.bytes + 1;
			et->key.Reset();
			m_entry_pool.Free(et);
		}	
		return et != NULL;
	}
	void Flush(){}
	void Expand(int capcity,double keybytes=0)
	{
		int len = m_hashmap.GetLength();
		if (capcity > len)
		{
            int newlength = qb::base::GetHashPrimeLargerThan(capcity);
			m_hashmap.Expand(newlength);
		}
	}
	int GetCount()const{ return m_hashmap.GetCount(); }
protected:
	Entry* Alloc(const void* key,int len, int rid)
	{
		Entry* et = m_entry_pool.Alloc();
		et->hashnext = et->hashprev = 0;
		
		//int len = strlen((const char*)key);
		m_mem_bytes += len + 1;
		char* ptr = new char[len + 1];
		memcpy(ptr, key, len);
		ptr[len] = 0;
		et->key.ptr = ptr;
		et->key.bytes = len;
		et->key.rid = rid;
		return et;
	}
};
	}//namespace ht
}//namespace qb
